const {
	ENUM_MEDIA_TYPE
} = require("../../static/enum")

/**
 * 获取文件尺寸大小
 * @param {String} filePath
 * @returns promise 返回 file size 或者 reject error
 */
function getFileSize(filePath) {
	return new Promise((resolve, reject) => {
		uni.getFileInfo({
			filePath,
			success: res => {
				const {
					size
				} = res;
				const result = Number(size) / 1000; // Byte 转 KB
				resolve(result)
			},
			fail: err => {
				reject('获取文件尺寸失败')
			}
		})
	})
}

/**
 * 压缩H5平台图片
 * @param {String} filePath 要压缩的文件路径
 * @param {Number} quality 压缩质量 0~100
 * @returns promise 返回压缩后的文件路径 或 压缩失败错误
 */
function compressH5Image(filePath, quality = 80) {
	return new Promise((resolve, reject) => {
		const img = new Image();
		img.src = filePath;
		img.onload = () => {
			const canvas = document.createElement('canvas');
			const ctx = canvas.getContext("2d");
			let maxWidth = 800; // 大尺寸图片可能引发内存溢出，先限制宽高再压缩
			let maxHeight = 800;
			let width = img.width;
			let height = img.height;
			if (width > maxWidth || height > maxHeight) {
				const ratio = Math.max(width / maxWidth, height / maxHeight);
				width = Math.floor(width / ratio);
				height = Math.floor(height / ratio);
			}
			canvas.width = width;
			canvas.height = height;
			ctx.drawImage(img, 0, 0, width, height);
			canvas.toBlob((blob) => {
				let file = new File([blob], img.src.split('/').pop(), {
					type: 'image/jpeg',
					lastModified: Date.now()
				});
				resolve(file)
			}, 'image/jpeg', quality / 100, )
		};
		img.onerror = (err) => {
			reject('图片压缩失败');
		}
	})
}

/**
 * 压缩非H5平台图片
 * @param {String} filePath 要压缩的文件路径
 * @param {Number} quality 压缩质量 0~100
 * @returns promise 返回压缩后的文件路径 或 压缩失败错误
 */
function compressOtherImage(filePath, quality = 80) {
	// 获取 uni.compressImage param 参数
	let composeCompressParamPromise = (filePath, quality) => {
		return new Promise((resolve, reject) => {
			let param = {
				src: filePath
			}
			if (filePath.includes('.jpg') || filePath.includes('.jpeg')) {
				param.quality = quality;
				resolve(param);
			} else {
				uni.getImageInfo({
					src: filePath,
					success: res => {
						const {
							width,
							height,
							path,
						} = res;
						param.compressWidth = width * (quality / 100);
						param.compressHeight = height * (quality / 100);
						resolve(param);
					},
					fail: err => {
						reject('获取图片信息失败');
					}
				})
			}
		})
	}
	// compress 方法 执行
	let compressFn = (param) => {
		return new Promise((resolve, reject) => {
			uni.compressImage({
				...param,
				success: res => {
					resolve(res.tempFilePath)
				},
				fail: err => {
					reject('图片压缩失败')
				}
			})
		})
	}
	return composeCompressParamPromise(filePath, quality).then(param => {
		return compressFn(param)
	})
}

/**
 * 压缩图片
 * @param {String} filePath 要压缩的文件路径
 * @param {Number} compressMaxSize  压缩最大尺寸 KB
 * @param {Number} quality 压缩质量 0~100 
 * @param {Number} compressCount 递归次数统计
 * @returns promise 返回压缩后的文件路径 或 压缩失败错误
 */
function compressImage(filePath, compressMaxSize = 0, quality = 80, compressCount = 0) {
	// 获取文件尺寸
	return getFileSize(filePath).then(size => {
		// 小于最大尺寸，压缩成功
		if (!compressMaxSize || size <= compressMaxSize) {
			return Promise.resolve(filePath)
		} else {
			// 超出递归次数限制，不再执行
			if (compressCount >= 5) {
				return Promise.reject('图片尺寸过大无法压缩');
			} else {
				let compressFn;
				// #ifdef H5
				compressFn = compressH5Image;
				// #endif
				// #ifndef H5
				compressFn = compressOtherImage;
				// #endif
				// 执行压缩
				return compressFn(filePath, quality).then(compressFilePath => {
					// 递归调用，检查尺寸，如果达标，返回最终地址，不达标，继续压缩
					return compressImage(compressFilePath, compressMaxSize, quality, compressCount + 1)
				})
			}
		}
	})
}

/**
 * 压缩视频
 * @param {String} filePath 要压缩的文件路径
 * @param {Number} compressMaxSize  压缩最大尺寸 KB
 * @param {Number} quality 压缩质量 0~100 
 * @param {Number} compressCount 递归次数统计
 * @returns promise 返回压缩后的文件路径 或 压缩失败错误
 */
function compressVideo(filePath, compressMaxSize = 0, quality = 80, compressCount = 0) {
	// 获取文件尺寸
	return getFileSize(filePath).then(size => {
		// 小于最大尺寸，压缩成功
		if (!compressMaxSize || size <= compressMaxSize) {
			return Promise.resolve(filePath)
		} else {
			// 超出递归次数限制，不再执行
			if (compressCount >= 5) {
				return Promise.reject('视频尺寸过大无法压缩');
			} else {
				// 执行压缩
				// #ifdef APP || MP-WEIXIN
				return new Promise((resolve, reject) => {
					let videoQuality;
					if (quality > 80) {
						videoQuality = 'high'
					} else if (quality <= 80 && quality > 40) {
						videoQuality = 'medium'
					} else {
						videoQuality = 'low'
					}
					uni.compressVideo({
						src: filePath,
						quality: videoQuality, // high | medium | low
						success: res => {
							resolve(res.tempFilePath)
						},
						fail: err => {
							reject('视频压缩失败');
						}
					})
				}).then(compressFilePath => {
					return compressVideo(compressFilePath, compressMaxSize, quality, compressCount + 1)
				})
				// #endif
				// #ifndef APP || MP-WEIXIN
				return Promise.reject('视频尺寸过大无法压缩');
				// #endif
			}
		}
	})
}

/**
 * 压缩媒体文件
 * @param {String} filePath 要压缩的文件路径
 * @param {ENUM_MEDIA_TYPE} imageType 媒体类型
 * @param {Number} compressMaxSize  压缩最大尺寸 KB
 * @param {Number} quality 压缩质量 0~100 
 * @returns promise 返回压缩后的文件路径 或 压缩失败错误
 */
function compressMedia(filePath, imageType, compressMaxSize = 0, quality = 80) {
	switch (imageType) {
		case ENUM_MEDIA_TYPE.IMAGE.value:
			return compressImage(filePath, compressMaxSize, quality);
		case ENUM_MEDIA_TYPE.VIDEO.value:
			return compressVideo(filePath, compressMaxSize, quality)
		default:
			return Promise.reject('compress unkown imageType');
	}
}

module.exports = {
	getFileSize,

	compressMedia,

	compressVideo,

	compressImage,
	compressH5Image,
	compressOtherImage
}